package auth

import (
	"cftgo/cftc"
	"cftgo/cftf/boot/app"
	"cftgo/cftf/db"
	"cftgo/cftf/ginhelper"
	"cftgo/cftf/uuid"
	"errors"
	"login/configcenter"
	"login/internal/common/constant"
	"login/model"
	"login/service/jwt"

	"github.com/gin-gonic/gin"
	"gorm.io/gorm"
)

type Auth struct {
}

type reqBodyObj struct {
	AppId  int32  `json:"app_id"`
	PlatId int32  `json:"plat_id"`
	Data   string `json:"data"`
}

func (this *Auth) Auth(c *gin.Context) {
	reqObj := new(reqBodyObj)
	if err := c.ShouldBindJSON(reqObj); err != nil {
		ginhelper.RspErr(c, 1, "params format error")
		return
	}
	if !configcenter.AllowAppLogin(reqObj.AppId) {
		ginhelper.RspErr(c, 2, "disallow login")
		return
	}
	switch reqObj.PlatId {
	case constant.CHANNEL_GUEST:
		this.guestAuth(c, reqObj)
	default:
		ginhelper.RspErr(c, 1, "params error")
		return
	}
}

func (this *Auth) rspAuthOk(c *gin.Context, accModel *model.Account) {
	{
		var m = model.AidBindAccount{}
		result := db.GetOrmDb(constant.ACCOUNT_DB).First(&m, map[string]interface{}{
			"app_id":      accModel.AppId,
			"plat_id":     accModel.PlatId,
			"plat_openid": accModel.PlatOpenId,
		})
		if result.Error != nil {
			if errors.Is(result.Error, gorm.ErrRecordNotFound) {
				if this.bindAccount(accModel) {
					ginhelper.RspErr(c, 500, "server internal error")
					return
				}
			} else {
				ginhelper.RspErr(c, 500, "server internal error")
				return
			}
		}
	}
	rspObj := &struct {
		ginhelper.CommonRspHead
		AccessToken  string        `json:"access_token"`
		RefreshToken string        `json:"refresh_token"`
		ExpiresIn    int64         `json:"expires_in"`
		ServerTime   int64         `json:"server_time"`
		AID          cftc.EntityId `json:"aid"`
	}{}
	if tokenString, expiresIn, err := jwt.GenerateToken(accModel.Aid.String(), accModel.CreatedAt); err == nil {
		rspObj.AccessToken = tokenString
		rspObj.RefreshToken = tokenString
		rspObj.ServerTime = app.GetRealSeconds()
		rspObj.ExpiresIn = expiresIn
		rspObj.AID = accModel.Aid
		ginhelper.RspData(c, rspObj)
	} else {
		ginhelper.RspErr(c, 500, "server internal error")
	}
}

func (this *Auth) bindAccount(accModel *model.Account) bool {
	bindModel := new(model.AidBindAccount)
	bindModel.Aid = accModel.Aid
	bindModel.AppId = accModel.AppId
	bindModel.PlatId = accModel.PlatId
	bindModel.PlatOpenId = accModel.PlatOpenId
	bindModel.PlatUnionId = accModel.PlatUnionId
	bindModel.CreatedAt = accModel.CreatedAt
	bindModel.UpdatedAt = accModel.UpdatedAt
	return db.GetOrmDb(constant.ACCOUNT_DB).Create(bindModel).Error == nil
}

func (this *Auth) createAccount(c *gin.Context, appId int32, platId int32, openId string, unionId *string) {
	accModel := new(model.Account)
	{
		accModel.Aid = cftc.EntityId(uuid.NewLockNodeUuid())
		accModel.AppId = appId
		accModel.PlatId = platId
		accModel.PlatOpenId = openId
		accModel.PlatUnionId = unionId
		accModel.CreatedAt = app.GetRealSeconds()
		accModel.UpdatedAt = app.GetRealSeconds()
		result := db.GetOrmDb(constant.ACCOUNT_DB).Create(accModel)
		if result.Error != nil {
			ginhelper.RspErr(c, 500, "server internal error")
			return
		}
		if !this.bindAccount(accModel) {
			ginhelper.RspErr(c, 500, "server internal error")
		}
	}
	this.rspAuthOk(c, accModel)
}
